#!/usr/bin/env python

"""
A simple symbloic simulator for symbolic worlds
like the VacuumCleanerWorld (after Russell and Norvig).
"""
 
import SocketServer, socket, sys, threading, time, string

def INIT(filename):
    path = filename.split("/")
    modulefile = path.pop() # module name
    module = modulefile.split(".")[0]
    search = string.join(path, "/")
    oldpath = sys.path[:] # copy
    sys.path.insert(0, search)
    print "Attempting to import '%s'..." % module 
    exec("import " + module + " as userspace")
    reload(userspace)
    print "Loaded '%s'!" % userspace.__file__
    sys.path = oldpath
    try:
        userspace.INIT
    except AttributeError:
        raise ImportError, "your program needs an INIT() function"
    retval = userspace.INIT()
    return retval

class Server(SocketServer.TCPServer):
    def __init__(self, connection, handler, gui):
        handler.gui = gui
        handler.connection = connection
        SocketServer.TCPServer.__init__(self, connection, handler)
                
class Handler(SocketServer.BaseRequestHandler):
    def handle(self):
        self.request.setblocking(0)
        self.gui.done = 0
        while not self.gui.done:
            try:
                request = self.request.recv(10240).strip()
                sockname = self.request.getsockname()
            except:
                time.sleep(.01)
                continue
            try:
                retval = self.gui.process(request, sockname)
            except:
                continue
            if request == "disconnect":
                break
            try:
                self.request.send(retval)
            except: # broken pipe, etc
                self.gui.done = 1
        self.request.close()

class Thread(threading.Thread):
    def __init__(self, gui, port):
        threading.Thread.__init__(self)
        self.gui = gui
        self.server = Server(('', port),  Handler, gui)
        try:
            self.server.socket.settimeout(1) # checks to see if need to quit
            #self.server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        except:
            print "WARN: entering deadlock zone; upgrade to Python 2.3 to avoid"

    def run(self):
        while not self.gui.quit:
            self.server.handle_request()
        self.gui.destroy()

if __name__ == "__main__":
    # argv can be -g for no graphics, too
    pid = int(sys.argv[1])  # pid of Pyro. If it stops, so should sim
    if sys.argv[2] == '-g':
        worldFile = sys.argv[3] # "world" file
    else:
        worldFile = sys.argv[2] # "world" file        
    if worldFile[-3:] != '.py':
        worldFile += '.py'
    gui = INIT(worldFile)
    for port in gui.ports:
        print "Simulator starting listener on port", port, "..."
        thread = Thread(gui, port)
        thread.start()
    gui.mainloop()
    #import profile
    #profile.run('gui.mainloop()', 'pyrobotsim.profile')
